home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1993 NeXT Computer, Inc. All rights reserved.
- */
-
- #import "ProAudioSpectrum16Registers.h"
- #import <driverkit/i386/ioPorts.h>
- #import <driverkit/generalFuncs.h>
-
- static inline
- void
- setBaseAddress(unsigned int baseAddress)
- {
- /*
- * To relocate the I/O addresses, two 8-bit values are written to the
- * Master Address Pointer (0x9a01):
- * (1) board ID value (valid settings are 0xbc-0xbf)
- * (2) base address shifted right by two positions
- */
- outb(MASTER_ADDRESS_POINTER, FIRST_BOARD_ID);
- outb(MASTER_ADDRESS_POINTER, (baseAddress) >> 2);
- }
-
- static inline
- filterControl_t
- getFilterControl()
- {
- union {
- filterControl_t reg;
- unsigned char data;
- } filterControl;
-
- filterControl.data = inb(FILTER_CONTROL);
-
- return (filterControl.reg);
- }
-
- static inline
- void
- setFilterControl(filterControl_t reg)
- {
- union {
- filterControl_t reg;
- unsigned char data;
- } filterControl;
-
- filterControl.reg = reg;
-
- outb(FILTER_CONTROL, filterControl.data);
- }
-
- static inline
- void
- enableAudioOutput(boolean_t enable)
- {
- filterControl_t filterControl = {0};
-
- filterControl = getFilterControl();
- filterControl.enableAudioOutput = enable;
- setFilterControl(filterControl);
- }
-
- static inline
- interruptControl_t
- getInterruptControl()
- {
- union {
- interruptControl_t reg;
- unsigned char data;
- } interruptControl;
-
- interruptControl.data = inb(INTERRUPT_CONTROL);
-
- return (interruptControl.reg);
- }
-
- static inline
- void
- setInterruptControl(interruptControl_t reg)
- {
- union {
- interruptControl_t reg;
- unsigned char data;
- } interruptControl;
-
- interruptControl.reg = reg;
-
- outb(INTERRUPT_CONTROL, interruptControl.data);
- }
-
- static inline
- interruptStatus_t
- getInterruptStatus()
- {
- union {
- interruptStatus_t reg;
- unsigned char data;
- } interruptStatus;
-
- interruptStatus.data = inb(INTERRUPT_STATUS);
-
- return (interruptStatus.reg);
- }
-
- static inline
- void
- setInterruptStatus(interruptStatus_t reg)
- {
- union {
- interruptStatus_t reg;
- unsigned char data;
- } interruptStatus;
-
- interruptStatus.reg = reg;
-
- outb(INTERRUPT_STATUS, interruptStatus.data);
- }
-
- static inline
- crossChannelControl_t
- getCrossChannelControl()
- {
- union {
- crossChannelControl_t reg;
- unsigned char data;
- } crossChannelControl;
-
- crossChannelControl.data = inb(CROSS_CHANNEL_CONTROL);
-
- return (crossChannelControl.reg);
- }
-
- static inline
- void
- setCrossChannelControl(crossChannelControl_t reg)
- {
- union {
- crossChannelControl_t reg;
- unsigned char data;
- } crossChannelControl;
-
- crossChannelControl.reg = reg;
-
- outb(CROSS_CHANNEL_CONTROL, crossChannelControl.data);
- }
-
- static inline
- sampleCounterControl_t
- getSampleCounterControl()
- {
- union {
- sampleCounterControl_t reg;
- unsigned char data;
- } sampleCounterControl;
-
- sampleCounterControl.data = inb(SAMPLE_COUNTER_CONTROL);
-
- return (sampleCounterControl.reg);
- }
-
- static inline
- void
- setSampleCounterControl(sampleCounterControl_t reg)
- {
- union {
- sampleCounterControl_t reg;
- unsigned char data;
- } sampleCounterControl;
-
- sampleCounterControl.reg = reg;
-
- outb(SAMPLE_COUNTER_CONTROL, sampleCounterControl.data);
- }
-
- static inline
- systemConfiguration1_t
- getSystemConfiguration1()
- {
- union {
- systemConfiguration1_t reg;
- unsigned char data;
- } systemConfiguration1;
-
- systemConfiguration1.data = inb(SYSTEM_CONFIGURATION_1);
-
- return (systemConfiguration1.reg);
- }
-
- static inline
- void
- setSystemConfiguration1(systemConfiguration1_t reg)
- {
- union {
- systemConfiguration1_t reg;
- unsigned char data;
- } systemConfiguration1;
-
- systemConfiguration1.reg = reg;
-
- outb(SYSTEM_CONFIGURATION_1, systemConfiguration1.data);
- }
-
- static inline
- systemConfiguration2_t
- getSystemConfiguration2()
- {
- union {
- systemConfiguration2_t reg;
- unsigned char data;
- } systemConfiguration2;
-
- systemConfiguration2.data = inb(SYSTEM_CONFIGURATION_2);
-
- return (systemConfiguration2.reg);
- }
-
- static inline
- void
- setSystemConfiguration2(systemConfiguration2_t reg)
- {
- union {
- systemConfiguration2_t reg;
- unsigned char data;
- } systemConfiguration2;
-
- systemConfiguration2.reg = reg;
-
- outb(SYSTEM_CONFIGURATION_2, systemConfiguration2.data);
- }
-
- static inline
- DMAChannelConfiguration_t
- getDMAChannelConfiguration()
- {
- union {
- DMAChannelConfiguration_t reg;
- unsigned char data;
- } DMAChannelConfiguration;
-
- DMAChannelConfiguration.data = inb(DMA_CHANNEL_CONFIGURATION);
-
- return (DMAChannelConfiguration.reg);
- }
-
- static inline
- void
- setDMAChannelConfiguration(DMAChannelConfiguration_t reg)
- {
- union {
- DMAChannelConfiguration_t reg;
- unsigned char data;
- } DMAChannelConfiguration;
-
- DMAChannelConfiguration.reg = reg;
-
- outb(DMA_CHANNEL_CONFIGURATION, DMAChannelConfiguration.data);
- }
-
- static inline
- boolean_t
- setDMAChannel(int channel)
- {
- static DMAChannelConfiguration_t DMAChannelConfiguration = {0};
- static const unsigned char DMAMap[] = {
- DMA_CHANNEL_0,
- DMA_CHANNEL_1,
- DMA_CHANNEL_2,
- DMA_CHANNEL_3,
- DMA_CHANNEL_NONE,
- DMA_CHANNEL_5,
- DMA_CHANNEL_6,
- DMA_CHANNEL_7,
- };
-
- if (DMAMap[channel] == DMA_CHANNEL_NONE)
- return FALSE;
-
- DMAChannelConfiguration.channel = DMAMap[channel];
- setDMAChannelConfiguration(DMAChannelConfiguration);
- return TRUE;
-
- }
-
- static inline
- IRQConfiguration_t
- getIRQConfiguration()
- {
- union {
- IRQConfiguration_t reg;
- unsigned char data;
- } IRQConfiguration;
-
- IRQConfiguration.data = inb(IRQ_CONFIGURATION);
-
- return (IRQConfiguration.reg);
- }
-
- static inline
- void
- setIRQConfiguration(IRQConfiguration_t reg)
- {
- union {
- IRQConfiguration_t reg;
- unsigned char data;
- } IRQConfiguration;
-
- IRQConfiguration.reg = reg;
-
- outb(IRQ_CONFIGURATION, IRQConfiguration.data);
- }
-
- static inline
- boolean_t
- setInterrupt(int interrupt)
- {
-
- static IRQConfiguration_t IRQConfiguration = {0};
- static const unsigned char IRQMap[] = {
- INTERRUPT_NONE,
- INTERRUPT_NONE,
- INTERRUPT_2,
- INTERRUPT_3,
- INTERRUPT_4,
- INTERRUPT_5,
- INTERRUPT_6,
- INTERRUPT_7,
- INTERRUPT_NONE,
- INTERRUPT_NONE,
- INTERRUPT_10,
- INTERRUPT_11,
- INTERRUPT_12,
- INTERRUPT_NONE,
- INTERRUPT_14,
- INTERRUPT_15
- };
-
- if (IRQMap[interrupt] == INTERRUPT_NONE)
- return FALSE;
-
- IRQConfiguration.interrupt = IRQMap[interrupt];
- setIRQConfiguration(IRQConfiguration);
- return TRUE;
- }
-
-
- static inline
- void
- setMasterOutputAttenuation(u_int channel, masterAttenuation_t attenuation)
- {
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- // avoid a warning
- channelSelection.data = 0;
-
- // select the master A mixer
- channelSelection.reg.selectAddress = MIXER_A_MASTER;
- channelSelection.reg.selectChannel = channel;
- channelSelection.reg.isTransfer = TRUE;
-
- outb(MIXER_CONTROL, channelSelection.data);
-
- // set the attenuation
- outb(MIXER_CONTROL, (char)attenuation);
- }
-
- static inline
- void
- setOutputAttenuation(u_int address, u_int channel, u_int attenuation)
- {
-
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- union {
- channelAttenuation_t reg;
- unsigned char data;
- } channelAttenuation;
-
- // avoid a warning
- channelSelection.data = 0;
- channelAttenuation.data = 0;
-
- channelSelection.reg.selectAddress = address;
- channelSelection.reg.selectChannel = channel;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- channelAttenuation.reg.attenuation = attenuation;
- channelAttenuation.reg.routeChannel = MIXER_A_ROUTE;
- channelAttenuation.reg.swapChannels = NORMAL_STEREO;
- outb(MIXER_CONTROL, channelAttenuation.data);
- }
-
- static inline
- void
- setMasterInputAttenuation(u_int channel, masterAttenuation_t attenuation)
- {
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- // avoid a warning
- channelSelection.data = 0;
-
- // select the master B mixer
- channelSelection.reg.selectAddress = MIXER_B_MASTER;
- channelSelection.reg.selectChannel = channel;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- // set the attenuation
- outb(MIXER_CONTROL, (char)attenuation);
- }
-
- static inline
- void
- setInputAttenuation(u_int address, u_int channel, u_int attenuation)
- {
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- union {
- channelAttenuation_t reg;
- unsigned char data;
- } channelAttenuation;
-
- // avoid a warning
- channelSelection.data = 0;
- channelAttenuation.data = 0;
-
- channelSelection.reg.selectAddress = address;
- channelSelection.reg.selectChannel = channel;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- channelAttenuation.reg.attenuation = attenuation;
- channelAttenuation.reg.routeChannel = MIXER_B_ROUTE;
- channelAttenuation.reg.swapChannels = NORMAL_STEREO;
- outb(MIXER_CONTROL, channelAttenuation.data);
-
- }
-
- /*
- * In the 3.1 release, the driver set the sample rate using the technique
- * described in the Developer Reference. Unfortunately, this was imprecise
- * due to rounding errors. The values were calculated as follows:
- *
- * 1193180 / (sample rate * channel count)
- * 1193180 / (44100 * 1) = 27 // 44.1 kHz mono
- * 1193180 / (44100 * 2) = 13 // 44.1 kHz stereo
- *
- * MediaVision has provided us with the calculateRate function which calculates
- * the sample rate with more precision. This technique (which also sets the
- * prescale register) is undocumented in their reference manual.
- *
- */
- static inline
- void
- calculateRate(u_int sampleRate, u_int *timer, u_int *prescale)
- {
- long targetRatio;
- long bestRatio;
- long testRatio;
- long bestDifference;
- long lastDifference;
- long testDifference;
- long p;
- long t;
-
- targetRatio = (441000L << 10) / sampleRate;
- bestRatio = 300L << 10;
- bestDifference = 7000L << 10;
- *prescale = 0;
- *timer = 0;
-
- for (p = 2; p < 256; p++) {
- lastDifference = 300L << 10;
-
- for (t = p+1; t < 256; t++) {
- testRatio = (t << 10) / p;
-
- if (testRatio == targetRatio) {
- bestRatio = testRatio;
- *prescale = p;
- *timer = t;
- return;
- }
-
- testDifference = testRatio - targetRatio;
-
- if (testDifference < 0)
- testDifference = -testDifference;
-
- if (testDifference > lastDifference)
- break;
-
- if (testDifference < bestDifference) {
- bestRatio = testRatio;
- bestDifference = testDifference;
- *prescale = p;
- *timer = t;
- }
-
- lastDifference = testDifference;
- }
- }
- }
-
- static inline
- void
- setSampleRateTimer(u_int rate)
- {
-
- u_int prescale;
- u_int timer;
-
- union {
- sampleRateTimer_t rate;
- unsigned char data[2];
- } sampleRateTimer;
-
-
- filterControl_t filterControl = {0};
- sampleCounterControl_t sampleCounterControl = {0};
-
- /*
- * Before setting the sample rate interval, be sure to select the
- * Sample Rate Timer using Local Timer Control Register (0x138b). Also
- * remember to set the Sample Rate Timer Gate of the Audio Filter Control
- * Register (0xb8a) to 0 before programming the timer.
- */
- filterControl = getFilterControl();
- filterControl.enableSampleRateTimer = FALSE;
- setFilterControl(filterControl);
-
- sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
- sampleCounterControl.selectMode = SAMPLE_RATE_MODE;
- sampleCounterControl.latchCounter = 3;
- sampleCounterControl.selectCounter = SAMPLE_RATE_COUNT;
- setSampleCounterControl(sampleCounterControl);
-
- switch (rate) {
-
- case 44100:
- timer = 20;
- prescale = 2;
- break;
-
- case 22050:
- timer = 40;
- prescale = 2;
- break;
-
- case 8012:
- timer = 110;
- prescale = 2;
- break;
-
- default:
- calculateRate(rate, &timer, &prescale);
- break;
- }
-
- sampleRateTimer.rate = timer;
-
- outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[0]);
- outb(SAMPLE_RATE_TIMER, sampleRateTimer.data[1]);
-
- outb(PRESCALE_DIVIDER, prescale & 0x0F);
-
- }
-
- static inline
- void
- setSampleBufferCounter(sampleBufferCounter_t count)
- {
- union {
- sampleBufferCounter_t count;
- unsigned char data[2];
- } sampleBufferCounter;
-
- filterControl_t filterControl = {0};
- sampleCounterControl_t sampleCounterControl = {0};
-
- filterControl = getFilterControl();
- filterControl.enableSampleBufferCounter = FALSE;
- setFilterControl(filterControl);
-
- sampleCounterControl.countFormat = BINARY_COUNT_FORMAT;
- sampleCounterControl.latchCounter = 3;
- sampleCounterControl.selectMode = SAMPLE_BUFFER_MODE;
- sampleCounterControl.selectCounter = SAMPLE_BUFFER_COUNT;
- setSampleCounterControl(sampleCounterControl);
-
- sampleBufferCounter.count = count;
- outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[0]);
- outb(SAMPLE_BUFFER_COUNTER, sampleBufferCounter.data[1]);
- }
-
- static inline
- void
- setMasterModeControl(masterModeControl_t mode)
- {
- union {
- masterModeControl_t reg;
- unsigned char data;
- } masterModeControl;
-
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
-
- // avoid a warning
- channelSelection.data = 0;
-
- channelSelection.reg.selectAddress = MASTER_MODE_CONTROL;
- channelSelection.reg.selectChannel = BOTH_CHANNELS;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- masterModeControl.reg = mode;
- outb(MIXER_CONTROL, masterModeControl.data);
- }
-
- static inline
- void
- setLoudnessFilter(boolean_t flag)
- {
- masterModeControl_t masterModeControl = {0};
-
- masterModeControl.loudnessFilter = flag;
- setMasterModeControl(masterModeControl);
- }
-
-
- static inline
- void
- setBassControl(unsigned char boost)
- {
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- // avoid a warning
- channelSelection.data = 0;
-
- channelSelection.reg.selectAddress = BASS_CONTROL;
- channelSelection.reg.selectChannel = BOTH_CHANNELS;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- outb(MIXER_CONTROL, boost);
- }
-
- static inline
- void
- setTrebleControl(unsigned char boost)
- {
- union {
- channelSelection_t reg;
- unsigned char data;
- } channelSelection;
-
- // avoid a warning
- channelSelection.data = 0;
-
- channelSelection.reg.selectAddress = TREBLE_CONTROL;
- channelSelection.reg.selectChannel = BOTH_CHANNELS;
- channelSelection.reg.isTransfer = TRUE;
- outb(MIXER_CONTROL, channelSelection.data);
-
- outb(MIXER_CONTROL, boost);
- }
-
- static inline
- void
- resetMixer()
- {
- setMasterOutputAttenuation(BOTH_CHANNELS,
- DEFAULT_MASTER_OUTPUT_ATTENUATION);
-
- setOutputAttenuation(PCM,
- BOTH_CHANNELS,
- DEFAULT_OUTPUT_ATTENUATION);
-
- /*
- * mute all other output channels
- */
- setOutputAttenuation(INPUT_MIXER_LOOPBACK,
- BOTH_CHANNELS,
- MUTE);
-
- setMasterInputAttenuation(BOTH_CHANNELS,
- DEFAULT_MASTER_INPUT_ATTENUATION);
-
- setInputAttenuation(MICROPHONE,
- BOTH_CHANNELS,
- DEFAULT_MICROPHONE_ATTENUATION);
-
- setInputAttenuation(EXTERNAL_LINE_IN,
- BOTH_CHANNELS,
- DEFAULT_INPUT_ATTENUATION);
-
- /*
- * mute all other input channels
- */
- setInputAttenuation(FM_SYNTHESIS,
- BOTH_CHANNELS,
- MUTE);
-
- setInputAttenuation(INTERNAL_LINE_IN,
- BOTH_CHANNELS,
- MUTE);
-
- setInputAttenuation(SPEAKER,
- BOTH_CHANNELS,
- MUTE);
-
- setInputAttenuation(SOUNDBLASTER,
- BOTH_CHANNELS,
- MUTE);
-
- /*
- * set treble and bass boost to 0db
- */
- setBassControl(DEFAULT_BASS_BOOST);
- setTrebleControl(DEFAULT_TREBLE_BOOST);
- }
-
-
-
- /*
- * resetHardware uses "magic" values recommended by MediaVision. These
- * settings are not always documented in the reference guide. In addition,
- * some of the values are specific to a particular version of the hardware.
- */
- static inline
- boolean_t
- resetHardware()
- {
- systemConfiguration1_t systemConfiguration1;
-
- union {
- interruptControl_t reg;
- unsigned char data;
- } interruptControl;
-
- unsigned char version;
-
- /*
- * The presence of the hardware is verified. The version bits in the
- * interrupt control register are read only.
- */
- interruptControl.data = inb(INTERRUPT_CONTROL);
-
- if (interruptControl.data == 0xff)
- return FALSE;
-
- version = interruptControl.reg.version;
- interruptControl.reg.version = 0;
-
- outb(INTERRUPT_CONTROL, interruptControl.data);
- interruptControl.data = inb(INTERRUPT_CONTROL);
-
- if (interruptControl.reg.version != version)
- return FALSE;
-
- /*
- * Turn off MPU and SoundBlaster emulation
- *
- outb(COMPATIBILITY_ENABLE, 0);
-
- /*
- * Turn off MPU and SoundBlaster interrupts
- */
- outb(EMULATION_CONFIGURATION, 0);
-
- /*
- * Sets wait state to 140ns period
- */
- outb(WAIT_STATE, WAIT_STATE_RESET);
-
- /*
- * D0 - resets FM
- * D1 - resets Codec
- * D2 - resets SoundBlaster
- * D4 - resets MVA508 Mixer
- */
- outb(AUDIO_MIXER, 0);
- outb(AUDIO_MIXER, AUDIO_MIXER_RESET);
-
- /*
- * This is required when using the prescale register for more precise
- * sample rate timing.
- */
- systemConfiguration1 = getSystemConfiguration1();
- systemConfiguration1.selectCompatibleClock = TRUE;
- setSystemConfiguration1(systemConfiguration1);
-
- outb(SYSTEM_CONFIGURATION_2, SYSTEM_CONFIGURATION_2_RESET);
- /*
- * D3 (invert bclk output)
- * D4 (use codec sync output)
- */
- outb(SYSTEM_CONFIGURATION_3, SYSTEM_CONFIGURATION_3_RESET);
-
- outb(SYSTEM_CONFIGURATION_4, SYSTEM_CONFIGURATION_4_RESET);
-
- /*
- * When a 16 bit Codec is attached, the Prescale counter is used to
- * set the ratio between the incoming Codec bit clock and the outgoing
- * master clock.
- */
- outb(PRESCALE_DIVIDER, PRESCALE_DIVIDER_RESET);
-
- resetMixer();
- return TRUE;
- }
-
-